package fileutil

import (
	"bufio"
	"errors"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

func SetHidden(source string) error {
	return setAttribute(source, syscall.FILE_ATTRIBUTE_HIDDEN)
}

func SetSystem(source string) error {
	return setAttribute(source, syscall.FILE_ATTRIBUTE_SYSTEM)
}

func SetNormal(source string) error {
	return setAttribute(source, syscall.FILE_ATTRIBUTE_NORMAL)
}

func setAttribute(source string, attrs uint32) error {
	filenameW, err := syscall.UTF16PtrFromString(source)
	if err != nil {
		return err
	}
	err = syscall.SetFileAttributes(filenameW, attrs)
	if err != nil {
		return err
	}
	return nil
}

// CustomMaKeDirectory
// sourceName  need create really name
// targetName  need display name
// dirParentPath dir parent path
func CustomMaKeDirectory(sourceName string, targetName string, dirParentPath string) error {
	const filename = "desktop.ini"
	const content = `
[.ShellClassInfo]
LocalizedResourceName=%v
Flags=0
[ViewState]
Mode=
Vid=
FolderType=Generic
`
	targetDir := filepath.Join(dirParentPath, sourceName)
	targetFilePath := filepath.Join(dirParentPath, sourceName, filename)
	targetFileContent := fmt.Sprintf(content, targetName)
	gbContent, encodingErr := simplifiedchinese.GB18030.NewEncoder().String(targetFileContent)
	if encodingErr != nil {
		return encodingErr
	}
	// if dir not exist, create it
	if _, dirExistedErr := os.Stat(targetDir); dirExistedErr != nil {
		if mkdirErr := os.MkdirAll(targetDir, os.ModePerm); mkdirErr != nil {
			return mkdirErr
		}
		if err := SetSystem(targetDir); err != nil {
			return err
		}
	}
	// if hidden ini file existed
	if _, err := os.Stat(targetFilePath); err == nil {
		if normalErr := SetNormal(targetFilePath); normalErr != nil {
			return err
		}
	}
	if err := os.WriteFile(targetFilePath, []byte(gbContent), os.ModePerm); err != nil {
		return err
	}
	if err := SetSystem(targetFilePath); err != nil {
		return err
	}
	if err := SetHidden(targetFilePath); err != nil {
		return err
	}
	return nil
}

func ReadCustomDirectoryName(source string) (string, error) {
	return ReadHiddenFile(source, func() (string, error) {
		return readDirectoryNameFromHiddenFile(source)
	})
}

func readDirectoryNameFromHiddenFile(source string) (string, error) {
	bytes, readIniErr := os.Open(source)
	if readIniErr != nil {
		return "", errors.New("iniReadErr")
	}
	LocalizedResourceName := ""
	scanner := bufio.NewScanner(bytes)
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		text := scanner.Text()
		if strings.Contains(text, "LocalizedResourceName") {
			LocalizedResourceName = strings.Split(text, "=")[1]
			break
		}
	}

	projectName, decodingErr := simplifiedchinese.GB18030.NewDecoder().String(LocalizedResourceName)
	if decodingErr != nil {
		return "", decodingErr
	}
	return projectName, nil
}

func ReadHiddenFile(source string, action func() (string, error)) (string, error) {
	// set file attribute as normal
	if err := SetNormal(source); err != nil {
		return "", err
	}
	// set file attribute as system and hidden
	defer func() {
		_ = SetSystem(source)
		_ = SetHidden(source)
	}()
	// do read file
	return action()
}
